package pers.cz.postgirl.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @program: PostGirl-panent
 * @description: 错误编码处理，初始化错误编码并缓存
 * @author: Cheng Zhi
 * @create: 2022-10-04 23:07
 **/
public final class ErrorCodeHolder {

    private static final Logger logger = LoggerFactory.getLogger(ErrorCodeHolder.class);

    private static ErrorCodeHolder instance;
    /**
     * 错误编码和描述缓存集合
     */
    private final Map<String, String> data = new ConcurrentHashMap<String, String>();

    /**
     * 多种错误类型集合
     */
    private List<Class<?>> errorCodeClasses;

    public static synchronized ErrorCodeHolder getInstance() {
        if (instance == null)
            instance = new ErrorCodeHolder();
        return instance;
    }

    ErrorCodeHolder() {
        addClass(ErrorCode.class);
    }

    /**
     * 注册一个用于描述错误代码的类
     * @param errorCodeClz
     */
    public synchronized void addClass(Class<?> errorCodeClz){
        if(errorCodeClasses == null){
            errorCodeClasses = new ArrayList<Class<?>>();
        }else{
            if(errorCodeClasses.contains(errorCodeClz)){
                logger.error("Please DO NOT setting ErrorCodeClass again and agian...");
            }
        }
        init(errorCodeClz);
        errorCodeClasses.add(errorCodeClz);
    }

    /**
     * 初始化将错误编码定义类中的错误编码和描述映射到map中
     * @param clazz
     */
    private void init(Class<?> clazz) {
        logger.debug("Initializing ErrorCode class:" + clazz.getName());
        Class<?> clz=clazz;
        while(clz!=Object.class){
            for (Field field : clz.getDeclaredFields()) {
                if (!Modifier.isStatic(field.getModifiers())) {
                    continue;
                }
                ErrorMessage msg = field.getAnnotation(ErrorMessage.class);
                if (msg == null)
                    continue;
                Object value = null;
                try {
                    value = field.get(null);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                if (value != null) {
                    data.put(String.valueOf(value), msg.text());
                }
            }
            clz=clz.getSuperclass();
        }
    }

    public String get(String errorCode) {
        return data.get(errorCode);
    }
}
